﻿
#include "GLSceneManager.h"
#include "GLGraphics.h"
#include "EMaterial.h"
#include "EUtil.h"

namespace Base3D
{
	//--------------------------------------------------------------------------

    GLSceneManager::GLSceneManager() : mLightEnable(true), mVisibleObjectNumber(0),
                                     mVisiblePolygonNumber(0), mTotalPolygonNumber(0), mTerrainMesh(nullptr)
	{
        //
		mCamera		= new ECamera();
		//mRenderList = new ERenderList4D;
	}

	//--------------------------------------------------------------------------

    GLSceneManager::~GLSceneManager()
	{
		for(auto iter = mMeshes.begin(); iter != mMeshes.end(); ++iter)
			SafeDelete(iter->second);
		for(auto iter = mUsedMesh.begin(); iter != mUsedMesh.end(); ++iter)
			SafeDelete(iter->second);

		mMeshes.clear();
		DestroyAllLights();
		SafeDelete(mCamera);
		//SafeDelete(mRenderList);
	}

	//--------------------------------------------------------------------------

	void GLSceneManager::drawString(const EString &str, EInt x, EInt y, const EColor &c)
	{
	    //
		GLGraphics::drawString(str, x, y, c);
	}

	//--------------------------------------------------------------------------

	// 创建一个模型实体
	EMesh* GLSceneManager::createMesh(const EString &name, const EString &meshName){
		auto iter = mMeshes.find(name);
		if (iter == mMeshes.end())
		{
			EMesh *mesh = nullptr;

			auto meshItr = mUsedMesh.find(meshName);
			if (meshItr != mUsedMesh.end())
			{
				mesh = meshItr->second->clone();
				mesh->mName = name;
			}
			else
			{
				mesh = new EMesh(name, meshName);
				mUsedMesh.insert(std::make_pair(meshName, mesh->clone()));
			}

			mMeshes.insert(std::make_pair(name, mesh));
			return mesh;
		}

		return iter->second;
	}

	void GLSceneManager::clearMesh(){
		for(auto iter = mMeshes.begin(); iter != mMeshes.end(); ++iter)
			SafeDelete(iter->second);

		mMeshes.clear();
	}

	//--------------------------------------------------------------------------

	// 获取指定的模型实体
	EMesh* GLSceneManager::getMesh(const EString &name){
		auto iter = mMeshes.find(name);
		if (iter == mMeshes.end())
		{
			return iter->second;
		}
		return nullptr;
	}

	//--------------------------------------------------------------------------

	// 销毁指定的模型实体
	void GLSceneManager::destroyMesh(const EString&name){
		auto iter = mMeshes.find(name);
		if (iter != mMeshes.end())
			SafeDelete(iter->second);
		mMeshes.erase(name);
	}

	//--------------------------------------------------------------------------

	// 指定开启/关闭灯光(全局)
	void GLSceneManager::enableLights(EBool enable){
		mLightEnable = enable;
		for (int i = 0; i < GetLightSize(); i++)
			getLight(i)->lightOn = enable;
	}

	//--------------------------------------------------------------------------

	// 创建一盏灯光
	ELight* GLSceneManager::createLight(LIGHT_TYPE lightType){
		EInt light = CreateLight(lightType);
		return getLight(light);
	}

	//--------------------------------------------------------------------------

	// 获得一个灯光, 如果灯光不存在, 则返回NULL
	ELight*	GLSceneManager::getLight(EInt id){
		return GetLight(id);
	}

	/*
	 * program
	 * buffer
	 */
    void GLSceneManager::render() {

    }
	//--------------------------------------------------------------------------

	// 更新
	void GLSceneManager::_render() {
        /*
        mCamera->render();

        Insert_Object4D_To_RenderList4D(renderList, object1->getObject(), TRANSFORM_TRANS, true);
        Insert_Object4D_To_RenderList4D(renderList, object->getObject(), TRANSFORM_TRANS, true);

        Local_To_World_RenderList4D(renderList, EVector4D::ZERO, TRANSFORM_TRANS);
        World_To_Screen_RenderList4D(renderList, mCamera->getFrustum());
        */
        mVisibleObjectNumber = 0;
        mTotalPolygonNumber = 0;

        // 更新摄像机
        mCamera->update();

        // 将所有模型添加到渲染列表
        for (auto &mMesh : mMeshes) {
            mTotalPolygonNumber += mMesh.second->getPolygonNumber();
            // 只对视野内的物体插入到渲染列表
            if (mMesh.second->isVisible()
                && !Cull_Object4D(mMesh.second->getObject(), mCamera->getFrustum(), CULL_BOX)) {
                mVisibleObjectNumber++;
                Insert_Object4D_To_RenderList4D(mRenderList, mMesh.second->getObject(),
                                                TRANSFORM_TRANS, true);
            }
        }

        // 渲染列表进行3D流水线处理
        // 局部坐标系变换到世界坐标系
        Local_To_World_RenderList4D(mRenderList, EVector4D::ZERO, TRANSFORM_TRANS);
        // 世界坐标系直接变换到屏幕坐标系
        // 世界坐标系-->背面消除-->摄像机坐标系变换-->
        // 裁剪-->光照计算-->透视变换-->屏幕变换
        World_To_Screen_RenderList4D(mRenderList, mCamera->getFrustum());

        // 当前可见多边形个数
        mVisiblePolygonNumber = mRenderList->polyData.size();

        // 执行渲染
        if (mCamera->getRenderMode() == RENDER_WIRE){
            Draw_RenderList4D_Wire(mRenderList);
        }else {
            Draw_RenderList4D_Texture_Solid(mRenderList);
        }
	}

	//--------------------------------------------------------------------------

	//void ESceneManager::render()
	//{
	//	if (mCamera->getRenderMode() == RENDER_WIRE)
	//		Draw_RenderList4D_Wire(mRenderList);
	//	else
	//		Draw_RenderList4D_Texture_Solid(mRenderList);
	//}

	EMesh* GLSceneManager::createTerrain(const EString& heightMapFileName,
		const EString &textureFileName, EFloat uTitle, EFloat vTitle, EFloat blockSize)
	{
		if (mTerrainMesh)
			SafeDelete(mTerrainMesh);

		Log("Loading Terrain HeightMap : #%s Texture : ...", heightMapFileName.c_str(), textureFileName.c_str());

		auto *heightMap		= new EBitmap(heightMapFileName);

		if (!heightMap->isValid() ||
            heightMap->getWidth() % 2 == 0 ||
            heightMap->getHeight() % 2 == 0)
		{
			SafeDelete(heightMap);
			return nullptr;
		}

		auto *mat			= new EMaterial();
		mat->bitmap				= new EBitmap(textureFileName);
		SetMaterial("Terrain", mat);

		EInt row				= heightMap->getHeight();
		EInt col				= heightMap->getWidth();

		// Y = 0.299R+0.587G+0.114B
		mTerrainMesh			= new EMesh();
		auto *obj			= new EObject4D();
		mTerrainMesh->mObject	= obj;

		obj->name				= "Terrain";
		obj->materialName		= "Terrain";
		obj->state				= EOBJECT_STATE_ACTIVE | EOBJECT_STATE_VISIBLE;
		obj->scale				= EVector4D(1,1,1);
		obj->worldPosition		= EVector4D::ZERO;
		obj->vertexNumber		= row * col;
		obj->polygonNumber		= (row - 1) * (col - 1) * 2;

		mTerrainMesh->mVertexNumber = obj->vertexNumber;
		mTerrainMesh->mPolygonNumber = obj->polygonNumber;

		// 定点列表
		obj->localList.reserve(obj->vertexNumber);
		obj->transformList.reserve(obj->vertexNumber);
		// 多边形列表
		obj->polygonList.reserve(obj->polygonNumber);

		EFloat offsetX = (col - 1) * blockSize / 2;
		EFloat offsetZ = (row - 1) * blockSize / 2;

		EFloat minY = 0, maxY = 0;
		EFloat u = uTitle / (col - 1);
		EFloat v = vTitle / (row - 1);
		for (EInt r = 0; r < row; r++)
		{
			for (EInt c = 0; c < col; c++)
			{
				EVertex4D vex;
				// 顶点坐标
				EColor color = heightMap->getPixel(c, r);
				vex.x	= c * blockSize - offsetX;
				vex.y	= 0.1f * (0.299f * color.r + 0.587f * color.g + 0.114f * color.b);
				vex.z	= r * blockSize - offsetZ;

				if (vex.y < minY)
					minY = vex.y;
				if (vex.y > maxY)
					maxY = vex.y;

				// 顶点UV
				vex.u	= c * u;
				vex.v	= r * v;

				obj->localList.push_back(vex);
				obj->transformList.push_back(vex);

				// 计算顶点索引
				if (r < row - 1 && c < col - 1)
				{
					EPolygon4D poly;
					poly.state		= EPOLY_STATE_ACTIVE;
					poly.attribute	= EPOLY_ATTR_VERTEX_POSITION | EPOLY_ATTR_VERTEX_UV;

					poly.verList	= &obj->transformList;

					poly.verIndex[0] = r * col + c;
					poly.verIndex[1] = (r + 1) * col + c;
					poly.verIndex[2] = r * col + c + 1;
					obj->polygonList.push_back(poly);

					poly.verIndex[0] = r * col + c + 1;
					poly.verIndex[1] = (r + 1) * col + c;
					poly.verIndex[2] = (r + 1) * col + c + 1;
					obj->polygonList.push_back(poly);
				}
			}
		}

		obj->maxBoundingBox		= EVector4D(offsetX, maxY, offsetZ);
		obj->minBoundingBox		= EVector4D(-offsetX, minY, -offsetZ);
		obj->maxRadius			= std::sqrt(offsetX * offsetX + offsetZ * offsetZ);

		SafeDelete(heightMap);
		mMeshes.insert(std::make_pair("Terrain", mTerrainMesh));
		// 设置不执行剔除操作
		mTerrainMesh->setCullFlag(false);

		Log("Terrain Load succeed!");
		return mTerrainMesh;
	}

	//--------------------------------------------------------------------------
}
